package com.xique.park.service.biz.service.impl.mini;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.alibaba.fastjson.parser.Feature;
import com.alipay.api.AlipayApiException;
import com.alipay.api.internal.util.AlipayEncrypt;
import com.alipay.api.internal.util.AlipaySignature;
import com.xique.common.core.domain.R;
import com.xique.common.core.utils.OrikaUtil;
import com.xique.door.api.dto.BaseUserDTO;
import com.xique.door.api.model.LoginAppUser;
import com.xique.park.api.dto.AppLoginBodyDTO;
import com.xique.park.bean.domain.BaseUser;
import com.xique.park.bean.domain.wechat.WeixinCode2Session;
import com.xique.park.bean.domain.wechat.WxUser;
import com.xique.park.service.biz.service.mini.IMiniLoginBizService;
import com.xique.park.service.service.IBaseUserService;
import com.xique.park.service.service.IWxUserService;
import com.xique.park.utils.AlipayUtils;
import com.xique.park.utils.WechatUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Map;

/**
 * @program: xq-cloud
 * @ClassName MiniLoginBizServiceImpl
 * @description:
 * @author: HdongSun
 * @create: 2022-08-25 16:52
 **/
@Service
@Slf4j
@RequiredArgsConstructor
public class MiniLoginBizServiceImpl implements IMiniLoginBizService {


    @Value("${wx.park.mini.appid}")
    private String appId;

    @Value("${wx.park.mini.secret}")
    private String secret;

    @Value("${alipay.park.mini.appid}")
    private String alipayAppid;

    @Value("${alipay.park.mini.publicKey}")
    private String alipayPublicKey;

    @Value("${alipay.park.mini.privateKey}")
    private String alipayPrivateKey;

    private final WechatUtils wechatUtils;

    private final IBaseUserService baseUserService;

    private final IWxUserService wxUserService;


    @Override
    public R<String> getPhone(String code) {
        R<String> result = wechatUtils.getPhone(appId, secret, code);
        if (R.FAIL == result.getCode()) {
            return R.fail(result.getMsg());
        }
        String phone = result.getData();
        return R.ok(phone);
    }

    @Override
    public R<LoginAppUser>  wxLogin(String phone, String code) {
        R<WeixinCode2Session> result = wechatUtils.getCode2Session(appId, secret, code);
        if (R.FAIL == result.getCode()) {
            return R.fail(result.getMsg());
        }
        WeixinCode2Session session = result.getData();

        //1、查询是否关注了公众号 关注则记录公众号openId
        List<WxUser> wxUsers = wxUserService.selectWxUserByUnionId(session.getUnionId());
        String wechatGzOpenid = "";
        if (CollUtil.isNotEmpty(wxUsers)) {
            wechatGzOpenid = wxUsers.get(0).getOpenId();
        }

        //2、手机号和openId组合查询到用户，则直接返回
        List<BaseUser> openIdAndPhoneUsers = baseUserService.selectBaseUserByParkMiniOpenIdAndPhone(session.getOpenId(), phone);
        if (!openIdAndPhoneUsers.isEmpty()) {
            BaseUser openIdAndPhoneUser = openIdAndPhoneUsers.get(0);
            if (StrUtil.isEmpty(openIdAndPhoneUser.getWechatUnionid()) || StrUtil.isEmpty(openIdAndPhoneUser.getWechatGzOpenid())) {
                openIdAndPhoneUser.setWechatUnionid(session.getUnionId());
                openIdAndPhoneUser.setWechatGzOpenid(wechatGzOpenid);
                baseUserService.updateBaseUser(openIdAndPhoneUser);
            }
            return R.ok(transformLoginAppUser(openIdAndPhoneUser));
        }

        List<BaseUser> openIdUsers = baseUserService.selectBaseUserByParkMiniOpenId(session.getOpenId());
        List<BaseUser> phoneUserList = baseUserService.selectBaseUserByPhone(phone);
        log.info("手机号和微信OPENID组合查询无法匹配用户，openIdUsers:{}，phoneUserList:{}",openIdUsers,phoneUserList);

        //3、openId查不到，手机号匹配到(手机号一样，openId不一样)
        if (CollUtil.isEmpty(openIdUsers) && CollUtil.isNotEmpty(phoneUserList)) {
            BaseUser phoneUser = phoneUserList.get(0);
            if (StrUtil.isNotEmpty(phoneUser.getParkWechatMiniOpenid())){
                log.error("[停车小程序]手机号已经被其他微信绑定,OPENID：{},微信返回手机号：{}，数据库用户对应手机号：{}", session.getOpenId(), phone, phoneUser.getCellphone());
                return R.fail("该手机号已经被其他微信绑定，请联系管理员！");
            }
            //给baseUser填充移动端信息
            phoneUser.setParkWechatMiniOpenid(session.getOpenId());
            phoneUser.setWechatUnionid(session.getUnionId());
            phoneUser.setSessionKey(session.getSessionKey());
            phoneUser.setWechatGzOpenid(wechatGzOpenid);
            baseUserService.updateBaseUser(phoneUser);
            return R.ok(transformLoginAppUser(phoneUser));
        }

        //4、openId查的到，手机号查不到(openId一样，手机号不一样)
        if (CollUtil.isNotEmpty(openIdUsers) && CollUtil.isEmpty(phoneUserList)) {
            BaseUser openIdUser = openIdUsers.get(0);
            if (StrUtil.isEmpty(openIdUser.getCellphone())) {
                //用户手机号为空，修改用户
                openIdUser.setCellphone(phone);
                openIdUser.setWechatUnionid(session.getOpenId());
                openIdUser.setWechatGzOpenid(wechatGzOpenid);
                baseUserService.updateBaseUser(openIdUser);
                return R.ok(transformLoginAppUser(openIdUser));
            }
            //一个微信可以绑定多个手机号登录
            log.error("[停车小程序]微信已经绑定了别的手机号,先创建新用户，openId：{},微信返回手机号：{}，数据库用户对应手机号：{}", session.getOpenId(), phone, openIdUser.getCellphone());
        }

        //5、手机号查不到，OPENID查不到，直接创建新用户
        BaseUser insert = new BaseUser();
        insert.setUserName(phone);
        insert.setCellphone(phone);
        insert.setParkWechatMiniOpenid(session.getOpenId());
        insert.setSessionKey(session.getSessionKey());
        insert.setWechatUnionid(session.getUnionId());
        insert.setWechatGzOpenid(wechatGzOpenid);
        baseUserService.insertBaseUser(insert);
        return R.ok(transformLoginAppUser(insert));
    }

    @Override
    public R<String> getZfbPhone(String jsonStr) {
        //1. 获取验签和解密所需要的参数
        Map<String, String> openapiResult = JSON.parseObject(jsonStr,
                new TypeReference<Map<String, String>>() {
                }, Feature.OrderedField);
        String signType = "RSA2";
        String charset = "UTF-8";
        String encryptType = "AES";
        String sign = openapiResult.get("sign");
        String content = openapiResult.get("response");

        //如果密文的
        boolean isDataEncrypted = !content.startsWith("{");
        boolean signCheckPass = false;

        //2. 验签
        String signContent = content;
        //你的小程序对应的支付宝公钥（为扩展考虑建议用appId+signType做密钥存储隔离）
        String signVeriKey = alipayPublicKey;
        //你的小程序对应的加解密密钥（为扩展考虑建议用appId+encryptType做密钥存储隔离）
        String decryptKey = "LWsccQ3SzG6JxMW2vl7MtA==";

        //如果是加密的报文则需要在密文的前后添加双引号
        if (isDataEncrypted) {
            signContent = "\"" + signContent + "\"";
        }
        try {
            signCheckPass = AlipaySignature.rsaCheck(signContent, sign, signVeriKey, charset, signType);
        } catch (AlipayApiException e) {
            //验签异常, 日志
            log.error(e.getMessage());
        }
        if(!signCheckPass) {
            //验签不通过（异常或者报文被篡改），终止流程（不需要做解密）
            return R.fail();
        }

        //3. 解密
        String phone = "";
        if (isDataEncrypted) {
            try {
                phone = AlipayEncrypt.decryptContent(content, encryptType, decryptKey, charset);
            } catch (AlipayApiException e) {
                //解密异常, 记录日志
                log.error(e.getMessage());
                return R.fail();
            }
        } else {
            phone = content;
        }
        return R.ok(phone);
    }

    @Override
    public R<LoginAppUser> zfbLogin(AppLoginBodyDTO dto) {
        String phone = dto.getPhone();
        String aliPayUserId = AlipayUtils.getUserId(dto.getCode(), alipayAppid, alipayPrivateKey, alipayPublicKey);

        //1、手机号和openid组合查询到用户，则直接返回
        List<BaseUser> aliPayUserIdAndPhoneUsers = baseUserService.selectBaseUserByAliPayUserIdAndPhone(aliPayUserId, phone);
        if (!aliPayUserIdAndPhoneUsers.isEmpty()) {
            return R.ok(transformLoginAppUser(aliPayUserIdAndPhoneUsers.get(0)));
        }

        List<BaseUser> alipayUsers = baseUserService.selectBaseUserByAlipayUserId(aliPayUserId);
        List<BaseUser> phoneUserList = baseUserService.selectBaseUserByPhone(phone);
        log.info("手机号和支付宝用户ID组合查询无法匹配用户，alipayUsers:{}，phoneUserList:{}",alipayUsers,phoneUserList);
        //2、aliPayUserId查不到，手机号匹配到
        if ( alipayUsers.isEmpty() && !phoneUserList.isEmpty()) {
            BaseUser phoneUser = phoneUserList.get(0);
            if (StrUtil.isNotEmpty(phoneUser.getAlipayUserId())) {
                log.error("手机号已经被其他支付宝绑定,手机号：{},aliPayUserId：{}，数据库用户对应aliPayUserId：{}", phone, aliPayUserId, phoneUser.getAlipayUserId());
                return R.fail("该手机号已经被其他微信绑定，请联系管理员！");
            }
            phoneUser.setAlipayUserId(aliPayUserId);
            baseUserService.updateBaseUser(phoneUser);
            return R.ok(transformLoginAppUser(phoneUser));
        }

        //3、aliPayUserId查的到，手机号查不到
        if (!alipayUsers.isEmpty() && phoneUserList.isEmpty()) {
            BaseUser alipayUser = alipayUsers.get(0);
            if (StrUtil.isEmpty(alipayUser.getCellphone())) {
                alipayUser.setCellphone(phone);
                baseUserService.updateBaseUser(alipayUser);
                return R.ok(transformLoginAppUser(alipayUser));
            }
            log.error("aliPayUserId已经绑定别的手机号,先创建新用户，aliPayUserId：{},支付宝返回手机号：{}，数据库用户对应手机号：{}", aliPayUserId, phone, alipayUser.getCellphone());
        }

        //4、aliPayUserId无法匹配，手机号无法匹配，创建新用户
        BaseUser baseUser = new BaseUser();
        baseUser.setUserName(phone);
        baseUser.setCellphone(phone);
        baseUser.setAlipayUserId(aliPayUserId);
        baseUserService.insertBaseUser(baseUser);
        return R.ok(transformLoginAppUser(baseUser));
    }

    private LoginAppUser transformLoginAppUser(BaseUser user) {
        LoginAppUser loginAppUser = new LoginAppUser();
        loginAppUser.setBaseUserId(user.getId());
        loginAppUser.setUserName(user.getUserName());
        loginAppUser.setOpenId(user.getParkWechatMiniOpenid());
        loginAppUser.setUnionId(user.getWechatUnionid());
        loginAppUser.setSessionKey(user.getSessionKey());
        loginAppUser.setZfbUserId(user.getAlipayUserId());
        loginAppUser.setUser(OrikaUtil.convert(user, BaseUserDTO.class));
        return loginAppUser;
    }

    @Override
    public R<LoginAppUser>  phoneLogin(String phone) {
        List<BaseUser> userList = baseUserService.selectBaseUserByPhone(phone);
        if (CollectionUtil.isNotEmpty(userList)) {
            if (userList.size() > 1) {
                return R.fail("当前手机号存在多个登录信息，请联系管理员处理");
            }
            BaseUser user = userList.get(0);
            return R.ok(transformLoginAppUser(user));
        }

        BaseUser insert = new BaseUser();
        insert.setUserName(phone);
        insert.setCellphone(phone);

        int count = baseUserService.insertBaseUser(insert);
        if (count <= 0) {
            return R.fail("注册失败");
        }

        return R.ok(transformLoginAppUser(insert));
    }
}
